package br.fagoc.easyds.datastructure;
import java.util.EmptyStackException;

import br.fagoc.easyds.cell.StackCell;
import br.fagoc.easyds.cell.StackCell;
import br.fagoc.easyds.exception.EmptyStructureException;
import br.fagoc.easyds.ui.jgraph.GraphCellManipulator;
import br.fagoc.easyds.ui.jgraph.GraphEdgeManipulator;
import br.fagoc.easyds.ui.jgraph.GraphManipulator;

import com.mxgraph.model.mxCell;
import com.mxgraph.model.mxICell;
import com.mxgraph.view.mxGraph;


public class Stack {

	private final double CELULA_LARGURA = 80;
	private final double CELULA_ALTURA = 50;
	private final double CELULA_EIXO_X_ORIGEM = 0;
	private final double CELULA_EIXO_Y_ORIGEM = 100;
	private final double CELULA_EIXO_Y_DESTINO = 20;
	private final double EIXO_X_LIMITE_REMOCAO = 0 - CELULA_LARGURA;
	private final double EIXO_Y_LIMITE_REMOCAO = CELULA_EIXO_Y_ORIGEM;
	private final double MODIFICADOR_EIXO_X = 100;
	
	private GraphCellManipulator graphCellManipulator;
	private GraphEdgeManipulator graphEdgeManipulator;
	private GraphManipulator graphManipulator;
	
	private java.util.Stack<StackCell> stack;
	
	public Stack(mxGraph graph) {
		stack = new java.util.Stack<StackCell>();
		
		this.graphManipulator = new GraphManipulator(graph);
		this.graphCellManipulator = new GraphCellManipulator(graph);
		this.graphEdgeManipulator = new GraphEdgeManipulator(graph);
	}
	
	
	public void push(String value){
		double xAxisCell = getCelulaEixoXDestino();
		double yAxisCell = getCelulaEixoYDestino();
		
		mxCell graphCell = graphCellManipulator.createRectangularCell(value, xAxisCell, yAxisCell);
		StackCell cell = new StackCell(graphCell);
		
		if(stack.size() > 0){
			StackCell parentCell = stack.get(stack.size()-1);
			mxICell edgeFromParentToCell = graphEdgeManipulator.createEdge(parentCell.getGraphCell(), graphCell);
			cell.setParentCell(parentCell);
			parentCell.setChildCell(cell, edgeFromParentToCell);	
		}		

		graphCellManipulator.horizontalTranslation(graphCell, CELULA_EIXO_X_ORIGEM, CELULA_EIXO_Y_ORIGEM, xAxisCell);
		graphCellManipulator.verticalTranslation(graphCell, xAxisCell, CELULA_EIXO_Y_ORIGEM, yAxisCell);
		
		if(cell.hasParent())
			graphEdgeManipulator.drawEdge(cell.getParentCell().getChildEdge(), cell.getParentCell().getGraphCell(), graphCell);
		
		graphCellManipulator.blinkCell(graphCell);
		
		stack.add(cell);
	}
	
	public void pop() throws EmptyStructureException {
		if(stack.size() == 0){
			throw new EmptyStructureException();
		}
		else{
			StackCell cell = stack.pop();
			
			graphCellManipulator.blinkCell(cell.getGraphCell());
			
			if(cell.hasParent()){
				graphEdgeManipulator.removeEdge(cell.getParentCell().getGraphCell(), cell.getParentCell().getChildEdge());
				cell.getParentCell().removeChild();
			}
			
			graphCellManipulator.verticalTranslation(cell.getGraphCell(), EIXO_Y_LIMITE_REMOCAO);
			graphCellManipulator.horizontalTranslation(cell.getGraphCell(), EIXO_X_LIMITE_REMOCAO);
			
			graphCellManipulator.removeCell(cell.getGraphCell());
		}
	}
	
	public void peek() throws EmptyStructureException{
		if(stack.size() == 0){
			throw new EmptyStructureException();
		}
		else{
			StackCell cell = this.stack.peek();
			mxCell graphCellReturned = graphCellManipulator.createRectangularCell(cell.getGraphCell().getValue().toString(), 
					cell.getGraphCell().getGeometry().getX(), cell.getGraphCell().getGeometry().getY());
			
			graphCellManipulator.blinkCell(cell.getGraphCell());
			
			graphCellManipulator.verticalTranslation(graphCellReturned, EIXO_Y_LIMITE_REMOCAO);
			graphCellManipulator.horizontalTranslation(graphCellReturned, EIXO_X_LIMITE_REMOCAO);
			
			graphCellManipulator.removeCell(graphCellReturned);
		}
	}
	
	public int size(){
		return this.stack.size();
	}
	
	public java.util.Stack<StackCell> getPilha(){
		return stack;
	}

	public double getCelulaLargura() {
		return CELULA_LARGURA;
	}
	public double getCelulaAltura() {
		return CELULA_ALTURA;
	}
	public double getCelulaEixoXOrigem() {
		return CELULA_EIXO_X_ORIGEM;
	}
	public double getCelulaEixoYOrigem() {
		return CELULA_EIXO_Y_ORIGEM;
	}
	public double getCelulaEixoYDestino() {
		return CELULA_EIXO_Y_DESTINO;
	}
	public double getCelulaEixoXDestino() {
		return 20 + (MODIFICADOR_EIXO_X * stack.size());
	}
}
